home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 329_01 / dprintf.doc < prev    next >
Text File  |  1990-02-12  |  12KB  |  290 lines

  1. dprintf Operating Instructions
  2. (C) August 30  1989  Arkin Asaf
  3. All rights reserved
  4.  
  5.  
  6. About dprintf
  7.  
  8. A respectable number of C libraries nowadays offer, usually at extra
  9. cost, their source code. You can put your hands on listings of just
  10. about any type and usage: windowing, graphics and data-base, to name but
  11. few. That is, to name but one -- the library that comes bundled with
  12. your compiler. 
  13.  
  14. It may happen that you will want to change features, not of a 3D-plot
  15. function, but of the more casual printf. Unless highly dedicated, want
  16. is all you can do about it. Correction: all you could do about it. 
  17.  
  18. Presented in source code, dprintf is a clone of the printf function. 
  19. With minute effort you can modify and adapt it to suit your needs; You
  20. will find dprintf is mostly portable and expandable: it easily extends
  21. to accommodate newly devised formats; it can print to almost all output
  22. destinations; and, not less important, it follows the ANSI standard to
  23. the dot. 
  24.  
  25.  
  26. Define printf
  27.  
  28. dprintf comes close in calling convention and operation to its
  29. originator, less one distinction: dprintf has a pointer-to-function as
  30. its first parameter. This pointer designates the function, resemblance
  31. to putchar(), which performs all output. Having th e function not
  32. preselected, dprintf enjoys unlimited choice of output destinations. 
  33. The pointer's definition and function prototypes follow:
  34.  
  35.  
  36.  
  37. typedef  int (*dprintf_fp)(int);
  38.  
  39. int   dprintf(dprintf_fp Func, const char *Format, ...);
  40.  
  41. int  vdprintf(dprintf_fp Func, const char *Format, va_list Args);
  42.  
  43.  
  44.  
  45. For those with amnesia and the unfamiliar with Standard C, a summarized
  46. description of all output formats, as defined in the ANSI standard and
  47. carried out by dprintf, appears in separate (see file "SYNOPSIS.DOC"). 
  48.  
  49.  
  50. Variations On dprintf
  51.  
  52. Similar to printf, dprintf accepts a variable arguments list. It then
  53. passes vdprintf a pointer to this list, along with pointers to the
  54. output function and format string. Having so little to do, dprintf
  55. tends to be rather small, as short as four statemen ts long. Such
  56. shortness makes it an easy target for changes. 
  57.  
  58. Intricate output destinations require a list of arguments to handle. 
  59. Since vdprintf accepts fixed arguments and is too long a function to
  60. exercise adaptability on, I advise that dprintf absorb all non-standard
  61. arguments, setting them for vdprintf's conven ience. To better clarify
  62. the point consider aprintf. This function allocates a memory block to
  63. store output in:
  64.  
  65.  
  66.  
  67. char  *aprintf_base;
  68.  
  69. char   aprintf_ofst;
  70.  
  71.  
  72.  
  73. const char  *aprintf(const char *Format, ...)
  74.  
  75. {
  76.  
  77.   va_list  Args;
  78.  
  79.  
  80.  
  81.   va_start(Args,Format);
  82.  
  83.   aprintf_ofst=0;
  84.  
  85.   aprintf_base=NULL;
  86.  
  87.   vdprintf(aprintf_out,Format,Args);
  88.  
  89.   aprintf_out('\0');
  90.  
  91.   va_end(Args);
  92.  
  93.   return  aprintf_base;
  94.  
  95. }
  96.  
  97.  
  98.  
  99. int  aprintf_out(int Char)
  100.  
  101. {
  102.  
  103.   aprintf_base=realloc(aprintf_base,aprintf_ofst+1);
  104.  
  105.   if (aprintf_base==NULL)
  106.  
  107.     return  EOF;
  108.  
  109.   aprintf_base[aprintf_ofst++]=Char;
  110.  
  111.   return  Char;
  112.  
  113. }
  114.  
  115.  
  116.  
  117. Still, vdprintf does not manage unaltered: Adding new formats is a
  118. recommended practice and you should attempt it often. Few suggestions
  119. being: binary and Roman numerals, file and path names, and printer
  120. control codes. In fact, dprintf insists you modify it prior to use: The
  121. pointer format is not covered by the ANSI standard, varying considerably
  122. between system architectures. It has been left for you to adapt %p to
  123. your system's taste. 
  124.  
  125.  
  126. The Workings Of vdprintf
  127.  
  128. You may find this section and the following two somewhat hard to follow:
  129. They describe the internal working of vdprintf in a stepwise manner. It
  130. is best that you refer to the listing while reading. 
  131.  
  132. As said earlier, vdprintf outputs characters by means of a function the
  133. programmer provides. Designated by a pointer, this function returns EOF
  134. upon output error. Rather than passing a pointer and return value
  135. through three levels of functions, a static p ointer (OutFunc) and
  136. longjmp buffer (dputc_buf -- for quick return) are defined. 
  137. Consequently, vdprintf's first actions involve assigning OutFunc a
  138. pointer and initializing dputc_buf. 
  139.  
  140. That done, the printing process begins: vdprintf scans the format string
  141. a character at a time, further processing %'s and echoing all other
  142. characters to the output. 
  143.  
  144. Following the % format sign come the flags -- zero or more from a set of
  145. five: -, +, space, 0 and #. Successive flags are parsed from the format
  146. string one by one: strchr() (see file "STRCHR.C") matches each potential
  147. flag against FlagsList, returning eit her NULL (not a flag) or a pointer
  148. to the flag in FlagsList. Simple pointer substraction and bit shifting
  149. then produce a bit mask, which ORs onto Flags. Later on vdprintf will
  150. AND Flags with Mask macros to establish whether certain flags have been
  151. mentioned or not. 
  152.  
  153. All flags read, vdprintf proceeds to gather the width and precision
  154. parameters. The width reads first (zero assumed, if absent): either as
  155. a numeric, deduced from digits in the format string, or an int, consumed
  156. from the variable arguments list, if an * r eplaces the numerals. You
  157. must be careful not to start the width with zero, for it will be
  158. considered a flag. Differently, the precision may begin with zero,
  159. being separated from the width by a period and read much the same way. 
  160. Do take note that not spec ifying the precision value (zero assumed by
  161. default), and omitting the precision altogether, including period (minus
  162. one assumed), hold dissimilar meanings, e.g. "%5.s" implies a
  163. zero-length string, whereas "%5s" implies a string of five or more
  164. character s. 
  165.  
  166. Last before the format letter comes the argument size: default, short
  167. (type h), long (l), or long double (L). The long size is applicable
  168. only for integers, the long double size for floating points. Default
  169. may be int, double or any specialized type, such as char for the %c
  170. format. The short type serves only to maintain some compatibility with
  171. scanf(), short arguments being automatically promoted to int and float
  172. arguments to double by the compiler. In effect, it is meaningless. 
  173.  
  174. Finally, the format letter gets read. It determines what course of
  175. action be taken to generate the right output. Most formats execute by
  176. auxiliary functions (on which you will read in the next section),
  177. keeping vdprintf short, or else it may fail to compi le. An output
  178. error or incorrect format specification at any point and vdprintf
  179. returns EOF; if all goes well, vdprintf returns the number of characters
  180. successfully printed. 
  181.  
  182.  
  183. vdprintf's Auxiliary Functions
  184.  
  185. Assisting vdprintf are five auxiliary functions: PrintDecimal,
  186. PrintRadix, PrintFloat, ToInteger and Print. The first three transform
  187. long ints, long unsigneds, and long doubles, respectively, into
  188. printable strings of digits: ToInteger transforms and Pri nt does the
  189. printing. This section discusses them all, except for PrintFloat. 
  190.  
  191. PrintDecimal (%d or %i formats) produces signed decimals: The long int
  192. it receives dissociates into prefix and value, the prefix holding the
  193. sign. Once ToInteger stringizes the value, Print outputs both the
  194. prefix and it. 
  195.  
  196. PrintRadix yields long unsigned decimals (%u format), octals (%o),
  197. hexadecimals (%x or %X) and pointers (%p). Their value is forever
  198. positive and so the prefix, obtained in the varient format (# flag
  199. present), denotes the value's type: nothing for decimal s, 0 for octals
  200. and 0x for hexadecimals. (Note that hexadecimal letters are in the same
  201. case as is the format letter.)
  202.  
  203. As delivered to you, vdprintf's PrintRadix utters 8-digit hexadecimal
  204. (upper case letters) pointers, which @ prefixes in the varient format. 
  205. Various system architectures impose different pointer representation,
  206. both in memory and in writing. It may be ess ential that you modify not
  207. only PrintRadix, but also vdprintf's switch construct: It assumes
  208. pointers to remain intact, cast to long unsigneds. Not all systems
  209. guarantee this to hold true. 
  210.  
  211. So numeric values can be printed, they must first convert into
  212. characters. ToInteger does just that. It t